package com.atguigu.gmall.item.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author lfy
 * @Description 自己写的分布式锁
 * @create 2023-07-18 14:35
 */
@Slf4j
@Component
public class MyDistLock {

    @Autowired
    StringRedisTemplate redisTemplate;

    public void lock(String token){ //阻塞式加锁
        //1、利用setnx 进行占位
//        while (!redisTemplate.opsForValue().setIfAbsent("lock", "1233")){
//            //加锁失败，再来一次
//        }
//        //设置过期时间
//        redisTemplate.expire("lock",10, TimeUnit.SECONDS);
        //以上两个必须是一个原子操作


        // 原子加锁 = 占坑 + 设置过期时间
        while (!redisTemplate.opsForValue().setIfAbsent("lock", token, 10, TimeUnit.SECONDS)) {

        }
    }

    public void unlock(String token){

        //为了不删除别人的锁，必须锁值用自己线程绑定的值
        //拿到锁值
//        String lock = redisTemplate.opsForValue().get("lock");
//        if(token.equals(lock)){
//            //这是我的锁
//            redisTemplate.delete("lock");
//        }else {
//            //这是别人的锁，啥也不要动
//        }
        //以上非原子操作，会删除别人的锁
        String lua = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        DefaultRedisScript<Long> script = new DefaultRedisScript<>(lua,Long.class);
        Long lock = redisTemplate.execute(script, Arrays.asList("lock"), token);
        //使用Lua脚本保证 判断+删除 是一个原子操作
        log.info("删锁："+lock);

    }
}
